﻿using System;
using System.Collections;
using System.Windows.Forms;

namespace FRS.Devices
{
    public class NETIO_230B : DeviceBase
    {
        //private const int PORT = 4444;
        private const int OUTPUTS = 4;
        private readonly Queue commandQueue;
        private Telnet.Telnet telnet;

        public NETIO_230B(Device device)
            : this(device.Address, device.Name)
        {
        }

        public NETIO_230B(string address, string name)
            : base(address, name)
        {
            commandQueue = Queue.Synchronized(new Queue());

            /* default output names */
            for (int i = 0; i < OUTPUTS; i++)
            {
                string output = "output " + i;
                OutputNames.Add(output);
                
                /* create the output treenodes */
                OutputTreeNode outputNode = new OutputTreeNode(this) { Text = output, OutputNr = i };
                RootNode.Nodes.Add(outputNode);
                OutputNodes.Add(outputNode);
                
                /*create the output menuitems*/
                OutputToolStripMenuItem outputMenuItem = new OutputToolStripMenuItem(i) { Text = output, CheckOnClick = true };
                outputMenuItem.Click += outputMenuItem_Click;
                RootMenuItem.DropDownItems.Add(outputMenuItem);
                OutputMenuItems.Add(outputMenuItem);
            }

            ToolStripSeparator tss = new ToolStripSeparator();
            RootMenuItem.DropDownItems.Add(tss);

            ToolStripMenuItem tsmi_on = new ToolStripMenuItem("all on");
            tsmi_on.Click += tsmi_on_Click;
            RootMenuItem.DropDownItems.Add(tsmi_on);

            ToolStripMenuItem tsmi_off = new ToolStripMenuItem("all off");
            tsmi_off.Click += tsmi_off_Click;
            RootMenuItem.DropDownItems.Add(tsmi_off);

            try
            {
                TelnetLogin();
            }
            catch (Exception)
            {
                IsAlive = false;
                telnet.Close();
                AliveStateChanged();
            }

            //telnet.Close();
        }

        private void TelnetLogin()
        {
            /* connect to device using KShell */
            telnet = new Telnet.Telnet();

            telnet.Login(Address, "admin", "admin", 5000);
        }

        void tsmi_on_Click(object sender, EventArgs e)
        {
            SetOutputs(0xFF, 0xFF);
        }

        void tsmi_off_Click(object sender, EventArgs e)
        {
            SetOutputs(0xFF, 0x00);
        }
        
        void outputMenuItem_Click(object sender, EventArgs e)
        {
            OutputToolStripMenuItem output = sender as OutputToolStripMenuItem;
            if (output != null) SetOutput(output.OutputNr, output.Checked ? 1 : 0);
        }

        protected override void Update()
        {
            try
            {
                if (!IsAlive)
                    TelnetLogin();
                
                IsAlive = true;
                AliveStateChanged();

                if (UpdateNames)
                {
                    for (int j = 0; j < OUTPUTS; j++)
                    {
                        /* commands in queue have a higher priority */
                        if (commandQueue.Count > 0) break;

                        /* get the characters 0-16 */
                        string name = TcpSendreceive(String.Format("port setup {0}", j + 1), 0).Split('"')[1];
                        
                        OutputNames[j] = name;
                    }
                    UpdateNames = false;
                }

                if (UpdateValues)
                {
                    string tmp = TcpSendreceive("port list", 0);

                    int i = Convert.ToInt32(tmp.Substring(4).TrimEnd(), 2);
                    OutputValues = ((i & 1) << 3) + ((i & (1 << 1)) << 1) + ((i & (1 << 2)) >> 1) + ((i & (1 << 3)) >> 3);
                }

                /* set commands are higher prior than get values and get names */
                while (commandQueue.Count > 0)
                    TcpSendreceive(commandQueue.Dequeue() as String, 0);
            //    CECC_TcpSendreceive(commandQueue.Dequeue() as Byte[]);
            }   
            catch(Exception)
            {
                IsAlive = false;
                telnet.Close();
                AliveStateChanged();
            }

            base.Update();
        }

        protected override string TcpSendreceive(string command, int port)
        {
            if (telnet.Connected)
                return telnet.SendCommand(command);

            return String.Empty;
        }
       
        public override void SetOutputName(int outputNr, string outputName)
        {
            commandQueue.Enqueue(String.Format("port setup {0} \"{1}\" manual 2 1", outputNr + 1, outputName));
            
            base.SetOutputName(outputNr, outputName);
        }

        public override void SetOutput(int outputNr, int value)
        {
            commandQueue.Enqueue(String.Format("port {0} {1}", outputNr + 1, value));

            base.SetOutput(outputNr, value);
        }

        public override void SetOutputs(int mask, int value)
        {
            string bin = Convert.ToString(value & mask, 2).PadLeft(4, '0');
            commandQueue.Enqueue(String.Format("port list {0}", bin.Substring(0, 4)));

            base.SetOutputs(mask, value);
        }
    }
}
